package com.gpj.learn.netty.reactor.single.server;

import com.gpj.learn.netty.reactor.single.handler.Acceptor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @className SingleReactorServer
 * @description TODO
 * @author GPJ
 * @date 2020/5/14 16:39
 * @version 1.0
 **/
public class SingleReactorServer implements Runnable{
    private ServerSocketChannel serverSocketChannel;
    private Selector selector;
    
    public SingleReactorServer init() throws IOException {
        this.serverSocketChannel = ServerSocketChannel.open();
        this.selector = Selector.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(9588));
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT, new Acceptor(serverSocketChannel, selector));
        return this;
    }

    @Override
    public void run() {
        // 判断线程是否中断
        while (!Thread.interrupted()) {
            System.out.println("Waiting for new event on port: " + serverSocketChannel.socket().getLocalPort() + "...");
            try {
                // 判断是否有事件触发
                if (selector.select() == 0)
                    continue;
            } catch (IOException e) {
                e.printStackTrace();
            }
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> it = selectedKeys.iterator();
            while (it.hasNext()) {
                dispatch((it.next()));
                it.remove();
            }
        }
    }

    /**
     * 处理对应事件
     * 获取触发事件的selectedKey，运行附件对象
     * @param selectedKey
     */
    private void dispatch(SelectionKey selectedKey) {
        Runnable r = (Runnable) (selectedKey.attachment()); // 根據事件之key綁定的對象開新線程
        if (r != null)
            r.run();
    }
}
